﻿using AspectCore.DynamicProxy;
using Microsoft.Extensions.Logging;
using Fall.Core.UnitOfWorks;
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Fall.Core.AOP
{
    /// <summary>
    /// 事务拦截器
    /// </summary>
    public class FallTransacationAttribute : AbstractInterceptorAttribute
    {
        /// <summary>
        /// 拦截方法
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            var method = context.ImplementationMethod ?? context.ServiceMethod;
            var logger = context.ServiceProvider.GetService(typeof(ILogger<FallTransacationAttribute>)) as ILogger<FallTransacationAttribute>;
            var unitOfWork = context.ServiceProvider.GetService(typeof(IUnitOfWork)) as IUnitOfWork;
            //对当前方法的特性验证
            //如果需要验证
            try
            {
                if (CheckAutoTran(method))
                {
                    await unitOfWork.BeginTransactionAsync();
                    await next(context);
                    await unitOfWork.CommitAsync();
                }
                else
                {
                    await next(context); //直接执行被拦截方法
                }
            }
            catch
            {
                logger.LogError($"自动提交事务失败:{method.Name}");
                throw;
            }
        }

        /// <summary>
        /// 验证方法需不需要自动提交事务
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        private static bool CheckAutoTran(MethodInfo method)
        {
            if ((method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(NotAutoTranAttribute)) is NotAutoTranAttribute
                || method.ReflectedType.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(NotAutoTranAttribute)) is NotAutoTranAttribute))
                return false;
            if (method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(AutoTranAttribute)) is AutoTranAttribute
                || method.ReflectedType.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(AutoTranAttribute)) is AutoTranAttribute
                || typeof(IFallAppService).IsAssignableFrom(method.ReflectedType))
                return true;
            return false;

        }

        /// <summary>
        /// 是不是异步方法（暂时没有用到）
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static bool IsAsyncMethod(MethodInfo method)
        {
            return (
                method.ReturnType == typeof(Task) ||
                (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
                );
        }

    }
}
